package org.tinygame;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import lombok.extern.slf4j.Slf4j;

/**
 * @Author: JLL
 * @Date: 2020/6/5 14:56
 *
 * 服务器入口类
 *
 * 	websocket相当于是接在HTTP协议之上的。一个长连接的实现。让它不要断开。
 *
 * 	理解netty的reactor模型，只需要想一个例子即可：
 * 	        餐馆：ServerBootstrap
 * 	        美女拉客：bossGroup
 * 	        服务员：workerGroup
 * 	        客人：client
 * 	        服务员负责点菜：监听的方式比轮询好
 */
@Slf4j
public class ServerMain {

    /**
     * 应用主函数
     */
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();   // 拉客的, 也就是故事中的美女
        EventLoopGroup workerGroup = new NioEventLoopGroup(); // 干活的, 也就是故事中的服务生

        //ServerBootstrap好比于是操作netty的一个界面
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup,workerGroup);
        b.channel(NioServerSocketChannel.class); // 服务器信道的处理方式（这是非阻塞的一个管道）
        //接收到消息后该怎么做？  这里写。
        b.childHandler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                //pipeline是核心。
                ch.pipeline().addLast(
                        new HttpServerCodec(), // Http 服务器编解码器
                        new HttpObjectAggregator(65535), // 内容长度限制，让它去接收websocket数据包的内容
                        new WebSocketServerProtocolHandler("/websocket"), // WebSocket 协议处理器, 在这里处理握手、ping、pong 等消息
                        new GameMsgHandler() // 自定义的消息处理器
                );
            }
        });

        try {
            // 绑定 12345 端口,
            // 注意: 实际项目中会使用 argArray 中的参数来指定端口号
            ChannelFuture f = b.bind(12345).sync();

            if (f.isSuccess()) {
                log.info("服务器启动成功!..");
            }

            // 等待服务器信道关闭,
            // 也就是不要立即退出应用程序, 让应用程序可以一直提供服务
            f.channel().closeFuture().sync();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }


}
